package org.oep;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import javax.microedition.rms.RecordStoreException;

public class MingleTracker {
	private JMingle parent;
	
	private final String defaultName = "???";
	private final String recordName = "MingleDB";
	private final Hashtable mingledDevices;
	private Vector lastScan;
	private Vector thisScan;
	
	public MingleTracker(JMingle parent) {
		this.parent = parent;
		thisScan = new Vector();
		lastScan = new Vector();
		mingledDevices = new Hashtable();
	}
	
	
	/*
	 * For external use
	 */
	//--------------------------------------------------------------//
	
	public int numberOfDevices() {
		if(mingledDevices != null)
			return mingledDevices.size();
		else
			return -1;
	}
	
	public int countSavedDevices() {
		try {
			return RecordStoreTools.countRecords(recordName);
		}
		catch(RecordStoreException e) {
			return -1;
		}
	}
	
	public Enumeration getDevices() {
		return mingledDevices.elements();
	}
	
	public void exportToRecordStore() {
		try {
			RecordStoreTools.export(mingledDevices, recordName);
		}
		catch(Exception e) {
			
		}
	}
	
	public void doLoad() {
		if(mingledDevices == null) {
			System.out.println("NULL OMG");
		}
		try {
			RecordStoreTools.load(recordName, mingledDevices);
		} catch (RecordStoreException e) {
			mingledDevices.clear();
		}
	}
	
	public void doMingle(String address, String name) {
		// Fix the default name
		if(name == null)
			name = defaultName;
		if(name.length() == 0)
			name = defaultName;
		
		String oldName = null;
		long time = -1;
		MingleNode node = null;
		
		// Show we've seen the address
		this.see(address);
		
		// Here, this device is not new to us
		if(mingledDevices.containsKey(address)){
			boolean updated = false;
			node = (MingleNode) mingledDevices.get(address);
			time = node.getLastSeen();
			node.markSeen();
			
			// In this case, we've seen it before, but it's name has changed
			if( shouldDoUpdate(node.getName(), name) ) {
				oldName = node.getName();
				node.setName(name);
				try {
					if(RecordStoreTools.update(node, recordName)) {
						updated = true;
						parent.tell("Updated: " + oldName + " -> " + name);
					}
				}
				catch (RecordStoreException e) {
					parent.tell(e.toString());
				}
			}
			
			// Nothing has changed about this node. Still, let's let the user know about it.
			else {
				if(!this.seen(address)) {
					parent.tell("Known: " + node.getName());
				}
			}
			
			// Things that happen once per run-in
			if(!this.seen(address)) {
				node.bump();
				if(time > 0)
					parent.tell("Seen " + Utils.friendlyTimeDiff(time) + " ago");
				
				// This is to update the time if it hasn't been already
				try {
					if(!updated)
						RecordStoreTools.update(node, recordName);
				}
				catch(RecordStoreException e) {
					parent.tell( e.toString() );
				}
				
			}
			
		}
		
		// It's brand-spanking new
		else {
			node = new MingleNode(name, address);
			node.bump();
			mingledDevices.put(address, node);
			
			// Add it to the Record Store
			try {
				RecordStoreTools.add(node, recordName);
				parent.tell("Saved: " + name);
			}
			catch(RecordStoreException e) {
				parent.tell(e.toString());
			}
		}

	}
	
	public void eraseAll() {
		mingledDevices.clear();
		thisScan.removeAllElements();
		lastScan.removeAllElements();
		parent.tell("Deleted mingles in memory");
		try {
			RecordStoreTools.delete(recordName);
			parent.tell("Deleted saved mingles");
		}
		catch(RecordStoreException e) {
			parent.tell(e.getMessage());
		}
	}
	
	public boolean seen(String address) {
		return lastScan.contains(address);
	}
	
	public void see(String address) {
		if(!thisScan.contains(address)) thisScan.addElement(address);
	}
	
	public void cycleSeenDevices() {
		for(int i = 0; i < lastScan.size(); i++) {
			Object address = lastScan.elementAt(i);
			if(!thisScan.contains(lastScan.elementAt(i))) {
				MingleNode n = (MingleNode) mingledDevices.get(address);
				parent.tell(n.getName() + " left");
			}
		}
		lastScan.removeAllElements();
		lastScan = thisScan;
		thisScan = new Vector();
	}
	
	public boolean isDefaultName(String address) {
		MingleNode n = (MingleNode) mingledDevices.get(address);
		String s;
		
		if(n != null)
			s = n.getName();
		else
			return false;
		
		return s.compareTo(defaultName) == 0;
	}
	
	private boolean shouldDoUpdate(String o, String n) {
		// Never update to the default name
		if(n.compareTo(defaultName) == 0) return false;
		
		// Never update if names are the same
		if(o.compareTo(n) == 0) return false;
		
		return true;
	}
}
